package ee.battleship.game;

import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.google.gson.Gson;

import ee.battleship.classes.Game;
import ee.battleship.classes.Player;
import ee.battleship.classes.Fleet;
import ee.battleship.classes.Shot;

@WebServlet("/GameControl")
public class GameControl extends HttpServlet {

	private static final long serialVersionUID = 1L;
	private static HashMap<Integer, Game> games = new HashMap<Integer, Game>();
	
	@Override
	public void init(ServletConfig config) throws ServletException {
		config.getServletContext().setAttribute("games", games);
		super.init(config);
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/plain");
		response.setCharacterEncoding("UTF-8");
		
		DBConnection connection = new DBConnection();
		HttpSession session = request.getSession();
		
		String action = request.getParameter("action");

		if (action != null && action.equals("joinGame")) {
			int gameId = -1;
			Player player = (Player) session.getAttribute("player");
			gameId = Integer.parseInt(request.getParameter("gameId"));
			if (gameId != -1) {
				try {
					Game gameInstance = games.get(gameId);
					gameInstance.addPlayer(player);
					session.setAttribute("game", gameInstance);
					connection.insertPlayerToGame(gameInstance, player);
					
					gameInstance.setStatus(1); // set Game status as started
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			
			response.sendRedirect("game.jsp");
		}
		
		if (action != null && action.equals("getAllPlayedGames")) {
			
			Map<Integer, Object> data = new HashMap<Integer, Object>();
			ArrayList<Game> games = connection.getAllPlayedGames();
			
			for (Game game : games) {
				
				Map<String, String> gameInformation = new HashMap<String, String>();
				gameInformation.put("id", Integer.toString(game.getId()));
				gameInformation.put("winner", game.getWinner().getName());
				gameInformation.put("player1", game.getPlayers().get(0).getName());
				gameInformation.put("player2", game.getPlayers().get(1).getName());
				
				data.put(game.getId(), gameInformation);
			}
			
			response.getWriter().print(new Gson().toJson(data));
		}
		
		if (action != null && action.equals("getLeaderBoard")) {
			Map<String, Object> data = new LinkedHashMap<String, Object>();
			ArrayList<Player> players = connection.getLeaderBoard();
			
			for (Player player : players) {
				Map<String,String> playerInformation = new HashMap<String, String>();
				playerInformation.put("id", Integer.toString(player.getId()));
				playerInformation.put("name", player.getName());
				playerInformation.put("wins", Integer.toString(player.getWins()));
				playerInformation.put("losses", Integer.toString(player.getLosses()));
				playerInformation.put("played_games", Integer.toString(player.getPlayedGames()));
				data.put(player.getName(), playerInformation);
			}
			
			response.getWriter().print(new Gson().toJson(data));
		}
		
	}
	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/plain");
		response.setCharacterEncoding("UTF-8");
		response.setHeader("pragma", "no-cache");
		
		DBConnection connection = new DBConnection();
		
		HttpSession session = request.getSession();
		Player player = (Player) session.getAttribute("player");
		Game game = (Game) session.getAttribute("game");
		
		String action = request.getParameter("action");
		
		if (action != null && action.equals("getGameId")) {
			if ((player != null) && (game != null)) {
				String gameId = String.valueOf(game.getId());
				response.getWriter().print(gameId);
			}
		}
		
		if (action != null && action.equals("getPlayerId")) {
			if (player != null) {
				String playerId = String.valueOf(player.getId());
				response.getWriter().print(playerId);
			}
		}
		
		if (action != null && action.equals("createGame")) {
			if (player != null) {
				game = connection.insertGame();
				
				try {
					connection.insertPlayerToGame(game, player);
				} catch (SQLException e) {
					e.printStackTrace();
				}
				games.put(game.getId(), game);
				session.setAttribute("game", game);
				game.addPlayer(player);
				response.getWriter().print("{\"gameId\" : "+ game.getId() + "}");
			}
		}
		
		if (action != null && action.equals("getGameList")) {

			String jsonString = "{\"games\": [";
	
			for (Map.Entry<Integer, Game> entry : games.entrySet()) {	
				if (entry.getValue().getPlayers().size() > 0) {
					jsonString += "{\"id\" : " + entry.getKey() + ", \"count\": " + entry.getValue().getPlayers().size() + ", \"status\": " + entry.getValue().getStatus() + ",\"creator\":\"" + entry.getValue().getPlayers().get(0).getName() +  "\"},";
				}
			}
			
			if (games.size() > 0) {
				jsonString = jsonString.substring(0, jsonString.length()-1);
			}
			
			jsonString += "]}";
			
			response.getWriter().print(jsonString);
		}
	
		
		if (action != null && action.equals("addFleets")) {
			if (player != null) {
				int id = Integer.valueOf(request.getParameter("id"));
				int size = Integer.valueOf(request.getParameter("size"));
				int top = Integer.valueOf(request.getParameter("top"));
				int left = Integer.valueOf(request.getParameter("left"));
				int orientation = Integer.valueOf(request.getParameter("orientation"));
				
				player.addShip(id, size, top, left, orientation);
			}
		}
		
		if (action != null && action.equals("getGameStatus")) {
			if (game.getStatus() == 1) {
				response.getWriter().print("{\"gameStarted\" : \"1\"}");
			} else {
				response.getWriter().print("{\"gameStarted\" : \"0\"}");
			}
		}
		
        if (action != null && action.equals("shoot")) {
        	if (player != null) {
    			int x = Integer.parseInt(request.getParameter("x"));
    	        int y = Integer.parseInt(request.getParameter("y"));
    	        
    	        Player enemy = game.getEnemy(player);
    	        
    	        int outcome = enemy.checkHit(x, y);
    	        if (outcome == 2) {
    	        	player.increaseScore();
    	        	
    	        	int score = player.getScore();
    	        	
    	        	Fleet wreck = enemy.getSunkenShip();
	                String id = String.valueOf(wreck.getId());
	                String top = String.valueOf(wreck.getTop());
	                String left = String.valueOf(wreck.getLeft());
	                String size = String.valueOf(wreck.getSize());
	                String orientation = String.valueOf(wreck.getOrientation());
	                
	                String resp = "{\"result\" : \"2\", ";
	                resp += "\"id\" : \"" + id + "\", ";
	                resp += "\"top\" : \"" + top + "\", ";
	                resp += "\"left\" : \"" + left + "\", ";
	                resp += "\"size\" : \"" + size + "\", ";
	                resp += "\"orientation\" : \"" + orientation + "\", ";
	                resp += "\"newScore\" : \"" + score + "\"}";
	             
	                response.getWriter().print(resp);
    	        } else if (outcome == 1) {
		        	response.getWriter().print("{\"result\" : \"1\"}");
		        } else {
		            response.getWriter().print("{\"result\" : \"0\"}");
		        }
        	}
        
        }
        	
    	if (action != null && action.equals("getEnemyShot")) {
    		if (player != null) {
				if (player.newEnemyShots()) {
    				String resp;
    				Shot enemyShot = player.getEnemyShot();
    				if (enemyShot.getStatus() != 2) {
						resp = "{\"result\" : \"" + String.valueOf(enemyShot.getStatus()) + "\", ";
						resp += "\"x\" : \"" + String.valueOf(enemyShot.getX()) + "\", ";
						resp += "\"y\" : \"" + String.valueOf(enemyShot.getY()) + "\"} ";
						response.getWriter().print(resp);
    				} else {
    					resp = "{\"result\" : \"2\", ";
    					resp += "\"x\" : \"" + String.valueOf(enemyShot.getX()) + "\", ";
    					resp += "\"y\" : \"" + String.valueOf(enemyShot.getY()) + "\", ";
    					resp += "\"id\" : \"" + String.valueOf(enemyShot.getID()) + "\"}";
    					response.getWriter().print(resp);
	                }
    			} else {
    				response.getWriter().print("{\"result\" : \"-1\"}");
    			}
    		}
    	}
    	
    	if (action != null && action.equals("enemyLeft")) {
    		if (game != null) {
    			boolean success = game.getPlayers().remove(player);
    			
    			if (success) {
    				game.setStatus(3);
    				connection.updateGame(game);
    				response.sendRedirect("lobby.jsp");
    			}
    		}
    	}
    	
    	if (action != null && action.equals("turnComplete")) { 
    		if (game != null) {
    			game.changeTurn();
    		}
		}
		 
		if (action != null && action.equals("getTurn")) { 	
			if (game != null && player != null) {
				while (game.getPlayers().size() < 2 && !game.hasEnemyLeft()) {
					try {
						Thread.currentThread().sleep(1000);
					} catch (InterruptedException ie) {
						ie.printStackTrace();
					}
				}
				
				int winner = -1; 		// Player winner id
				boolean isMyTurn = game.isMyTurn(player);
				
				if (!game.hasEnemyLeft()) {
					
					
					Player enemy = game.getEnemy(player);
					if (player.getScore() == 10) { 
						winner = player.getId();
					} else if (enemy.getScore() == 10) {
						winner = enemy.getId();
					}

					if (winner != -1) {
						if (game.getStatus() != 2) {
							game.setStatus(2);
							if (player.getScore() == winner) {
								player.increaseWins();
								enemy.increaseLosses();
							} else {
								enemy.increaseWins();
								player.increaseLosses();
							}
							
							enemy.increasePlayedGames();
							player.increasePlayedGames();
							connection.updatePlayer(player);
							connection.updatePlayer(enemy);
							connection.updateGame(game);
						}
					}
				}
			
				if (game.hasEnemyLeft()) {
					games.remove(game.getId());
					player.resetPlayerMoves();
					response.getWriter().print("{\"myTurn\" : \"" + String.valueOf(isMyTurn) + "\", \"enemyLeft\" : \"1\", \"winner\" : \"" + winner + "\"}");
				} else {
					response.getWriter().print("{\"myTurn\" : \"" + String.valueOf(isMyTurn) + "\", \"enemyLeft\" : \"0\", \"winner\" : \"" + winner + "\"}");
				}
			}
		}

		response.getWriter().flush();
	}
}
